package com.songqintuan.common.dal.ibatis.dao;

import java.io.Serializable;

import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.orm.ObjectRetrievalFailureException;

import com.songqintuan.common.bean.GenericsUtils;



/** 
#  * 负责为单个Entity 提供CRUD操作的IBatis DAO基类. 
#  * <p/> 
#  * 子类只要在类定义时指定所管理Entity的Class, 即拥有对单个Entity对象的CRUD操作. 
#  *  
#  * <pre> 
#  * public class UserManagerIbatis extends IBatisEntityDao<User> { 
#  * } 
#  * </pre> 
#  */
public class IBatisEntityDao<T, PK extends Serializable> extends IBatisGenericDao<T,PK> {  
	   
	/** 
	#   * DAO所管理的Entity类型. 
	#   */  
	protected Class<T> entityClass;  
	 
	protected String primaryKeyName;  
	
	protected Class<PK> pkClass;
	 
	protected T t; 
	/** 
	 * 在构造函数中将泛型T.class赋给entityClass. 
	 */  
	
	public void setEntityClass(Class<T> type) {
		this.entityClass = type;
	}
	
	public void setPKClass(Class<PK> pkClass) {
		this.pkClass = pkClass;
	}
	
	@SuppressWarnings("unchecked")  
	public IBatisEntityDao() {  
	 entityClass = (Class<T>) GenericsUtils.getSuperClassGenricType(getClass());  
	}  
	 
	/** 
	 * 根据属性名和属性值查询对象. 
	 *  
	 * @return 符合条件的对象列表 
	 * @throws SQLException  
	 */  
	public List<T> findBy(String property, Object value) throws SQLException {  
	 return findBy(getEntityClass(), property, value);  
	}  
	  
	/** 
	 * 根据属性的名值对查询对象 
	 * @param map 
	 * @return 
	 * @throws SQLException  
	 */  
	public List<T> find(Map<String, Object> map) throws SQLException{  
	 return find(getEntityClass(), map);  
	}  
	  
	/** 
	 * 根据属性的名值对查询唯一对象 
	 * @param map 
	 * @return 
	 * @throws SQLException 
	 */  
	public T findUniqueByMap(Map<String, Object> map) throws SQLException{  
	 List<T> list = find(getEntityClass(), map);  
	 if(list == null || list.size() <= 0){  
	  return null;  
	 }   
	 return list.get(0);  
	}  
	 
	/** 
	 * 根据属性名和属性值以Like AnyWhere方式查询对象. 
	 * @throws SQLException  
	 */  
	public List<T> findByLike(String name, String value) throws SQLException {  
	 return findByLike(getEntityClass(), name, value);  
	}  
	 
	/** 
	 * 根据属性名和属性值查询单个对象. 
	 *  
	 * @return 符合条件的唯一对象 
	 */  
	public T findUniqueBy(String name, Object value) {  
	 return findUniqueBy(getEntityClass(), name, value);  
	}  
	 
	/** 
	 * 根据ID获取对象. 
	 *  
	 * @throws BaseException 
	 * @throws SQLException  
	 */  
	public T get(PK id) throws Exception, SQLException {  
	 return findById(getEntityClass(), id);  
	}  
	 
	/** 
	 * 获取全部对象. 
	 * @throws SQLException  
	 */  
	public List<T> getAll() throws SQLException {  
	 return getAll(getEntityClass());  
	}  
	 
	/** 
	 * 取得entityClass. 
	 * <p/> 
	 * JDK1.4不支持泛型的子类可以抛开Class<T> entityClass,重载此函数达到相同效果。 
	 */  
	protected Class<T> getEntityClass() {  
	 return entityClass;  
	}  
	 
	public String getPrimaryKeyName() {  
	 if (StringUtils.isEmpty(primaryKeyName))  
	  primaryKeyName = "id";  
	 return primaryKeyName;  
	}  
	 
	protected T getPrimaryKeyValue(T o) throws NoSuchMethodException, IllegalAccessException,  
	  InvocationTargetException, InstantiationException {  
	 return (T)PropertyUtils.getProperty(entityClass.newInstance(), getPrimaryKeyName());  
	}  
	 
	/** 
	 * 根据ID移除对象. 
	 * @throws SQLException  
	 */  
	public int deleteById(PK id) throws SQLException {  
	 return deleteById(getEntityClass(), id);  
	}  
	 
	/** 
	 * 保存对象. 为了实现IEntityDao 我在内部使用了insert和upate 2个方法. 
	 * @throws SQLException  
	 */  
	public void saveOrUpdate(T o) throws SQLException {  
	 Object primaryKey;  
	 try {  
	  primaryKey = getPrimaryKeyValue(o);  
	 } catch (Exception e) {  
	  throw new ObjectRetrievalFailureException(entityClass, e);  
	 }  
	 
	 if (primaryKey == null)  
	  insert(o);  
	 else  
	  update(o);  
	}  
	 
	public void setPrimaryKeyName(String primaryKeyName) {  
	 this.primaryKeyName = primaryKeyName;  
	}  
	 
	public String getIdName(Class<?> clazz) {  
	 return "id";  
	} 
	
	public Integer count(String propertyName, Object propertyValue) throws Exception, SQLException {
		return count(getEntityClass(), propertyName, propertyValue);
	}
	
	public Integer countLikeByMap(String[] propertyNames, Object[] propertyValues) throws Exception, SQLException {
		return countLikeByMap(getEntityClass(), propertyNames, propertyValues);
	}
	
	public void deleteByIdsMap(List<PK> ids, String[] properties, Object[] propertyValues) throws Exception, SQLException {
		deleteByIdsMap(getEntityClass(),ids, properties, propertyValues);
	}
	
	public int deleteByMap(String[] properties, Object[] propertyValues) throws Exception {
		return deleteByMap(getEntityClass(), properties, propertyValues);
	}
	
	public int update(PK id, String[] properties, Object[] propertyValues) throws Exception {
		return update(getEntityClass(), id, properties, propertyValues);
	}
	
	public int updateByIdsMap(List<PK> ids,String[] properties, Object[] propertyValues) throws Exception{
		return  updateByIdsMap(getEntityClass(), ids, properties, propertyValues);
	}
	
} 
